package com.main.meldungsverwaltung;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.sql.Timestamp;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.http.client.utils.URIBuilder;
import org.jdesktop.xswingx.PromptSupport;

import datenverwaltung.GPSKoordinaten;
import datenverwaltung.Meldung;
import datenverwaltung.MeldungErstellenThread;
import datenverwaltung.MeldungVerwaltenThread;
import datenverwaltung.MeldungsDownload;
import datenverwaltung.TrackerDownloadThread;
import datenverwaltung.TrackerInfoDownload;
import datenverwaltung.TrackerVerwaltenThread;
import datenverwaltung.TrackerVerwaltungAction;
import edu.stanford.ejalbert.BrowserLauncher;
import edu.stanford.ejalbert.exception.BrowserLaunchingInitializingException;
import edu.stanford.ejalbert.exception.UnsupportedOperatingSystemException;

public class GUI extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private static final String title = "Verkehrsinfo - Meldungsverwaltung";
	private static final String[] meldungsTypen = { "", "Stau", "Radar",
			"Unfall" };
	public static boolean running = true;
	private TrackerInfoDownload trackerInfoDownload;
	private JTable table;
	public static final String XML_FILENAME = "tracker.xml";
	private JProgressBar ladeBalken;
	public static final String TRACKER_ID_RADIO2000 = "2000";

	public static void main(String[] args) {
		GUI g = new GUI();
	}

	/**
	 * Erstellen der Benutzeroberfläche. Setzen der Listener für alle
	 * Komponenten, die einen benötigen.
	 */
	public GUI() {
		this.setBounds(300, 50, 1320, 900);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setTitle(title);
		this.setLayout(new BorderLayout());

		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e2) {
			e2.printStackTrace();
		} catch (InstantiationException e2) {
			e2.printStackTrace();
		} catch (IllegalAccessException e2) {
			e2.printStackTrace();
		} catch (UnsupportedLookAndFeelException e2) {
			e2.printStackTrace();
		}

		JPanel basisPanel = new JPanel(new GridLayout(1, 2));
		JPanel infoPanel = new JPanel(new GridBagLayout());
		JPanel meldungsPanel = new JPanel(new GridLayout(8, 1));
		JPanel trackerPanel = new JPanel(new GridLayout(3, 1));

		JMenuBar statusLeiste = new JMenuBar();
		ladeBalken = new JProgressBar();
		ladeBalken.setSize(200, 100);
		JPanel ladePanel = new JPanel();
		ladePanel.add(new JLabel("Meldung: "));
		ladePanel.add(ladeBalken);
		statusLeiste.add(ladePanel);

		final JProgressBar tLadeBalken = new JProgressBar();
		tLadeBalken.setSize(200, 100);
		JPanel tLadePanel = new JPanel();
		tLadePanel.add(new JLabel("Trucker: "));
		tLadePanel.add(tLadeBalken);
		statusLeiste.add(tLadePanel);

		table = new JTable();
		final MeldungsDownload meldungsDownload = new MeldungsDownload(table);
		meldungsDownload.start();
		table.setRowHeight(30);
		table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		table.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16));

		meldungsPanel.setBorder(BorderFactory.createTitledBorder(
				BorderFactory.createLineBorder(Color.LIGHT_GRAY), "Meldung"));
		trackerPanel.setBorder(BorderFactory.createTitledBorder(
				BorderFactory.createLineBorder(Color.LIGHT_GRAY), "Trucker"));

		// final LabelTextField art = new LabelTextField("Art", false);
		final JComboBox<String> art = new JComboBox<String>();
		for (int i = 0; i < meldungsTypen.length; i++)
			art.addItem(meldungsTypen[i]);

		final LabelTextField ort = new LabelTextField("Ort", false);
		final LabelTextField beschreibung = new LabelTextField("Beschreibung",
				true);
		final LabelTextField zeit = new LabelTextField("Erstellzeit", false);
		final LabelTextField aktive = new LabelTextField("Aktiv-Angaben", false);
		final LabelTextField inaktive = new LabelTextField("Inaktiv-Angaben",
				false);
		final LabelTextField zuverl = new LabelTextField("Zuverlässigkeit",
				false);
		zeit.setReadOnly();
		aktive.setReadOnly();
		inaktive.setReadOnly();
		zuverl.setReadOnly();
		JButton ändernButton = new JButton("Ändern");
		JButton inaktivButton = new JButton("Inaktiv schalten");
		JButton meldungLöschenButton = new JButton("Meldung löschen");
		meldungLöschenButton
				.setToolTipText("Löscht die Meldung vollständig aus der Datenbank");
		JButton meldungErstellenButton = new JButton("Meldung erstellen");
		meldungErstellenButton
				.setToolTipText("Öffnet einen Dialog zum Erstellen einer Meldung");

		final LabelTextField trackerID = new LabelTextField("Trucker - ID",
				false);
		final LabelTextField trackerZuverl = new LabelTextField(
				"Zuverlässigkeit", false);
		trackerID.setReadOnly();
		trackerZuverl.setReadOnly();

		JButton alleTrackerAnzeigen = new JButton("Alle Trucker anzeigen");
		alleTrackerAnzeigen
				.setToolTipText("Zeigt alle vorhandenen Trucker in einer Tabelle an");
		JButton löschenButton = new JButton("Trucker löschen");
		löschenButton
				.setToolTipText("Löscht den Trucker und alle seine Meldungen aus der Datenbank");
		JButton trackerErstellenButton = new JButton("neuen Trucker generieren");
		trackerErstellenButton
				.setToolTipText("Erstellt einen neuen Trucker in der Datenbank und zeigt die generierte ID und das Passwort an");
		JButton trackerEintragenButton = new JButton("Trucker eintragen");
		trackerEintragenButton
				.setToolTipText("Trägt einen Trucker mit einer bestimmten ID in die Datenbank ein");

		Font buttonFont = new Font(Font.SANS_SERIF, Font.PLAIN, 16);
		art.setFont(buttonFont);
		ändernButton.setFont(buttonFont);
		inaktivButton.setFont(buttonFont);
		meldungLöschenButton.setFont(buttonFont);
		meldungErstellenButton.setFont(buttonFont);
		löschenButton.setFont(buttonFont);
		trackerErstellenButton.setFont(buttonFont);
		trackerEintragenButton.setFont(buttonFont);
		alleTrackerAnzeigen.setFont(buttonFont);

		JPanel meldungGridPanel = new JPanel(new GridLayout(2, 2));
		JPanel mButtonPanel1 = new JPanel();
		JPanel mButtonPanel2 = new JPanel();
		JPanel mButtonPanel3 = new JPanel();
		JPanel mButtonPanel4 = new JPanel();
		mButtonPanel1.add(ändernButton);
		mButtonPanel2.add(inaktivButton);
		mButtonPanel3.add(meldungLöschenButton);
		mButtonPanel4.add(meldungErstellenButton);
		meldungGridPanel.add(mButtonPanel1);
		meldungGridPanel.add(mButtonPanel2);
		meldungGridPanel.add(mButtonPanel3);
		meldungGridPanel.add(mButtonPanel4);

		JPanel trackerGridPanel = new JPanel(new GridLayout(2, 2));
		JPanel tButtonPanel1 = new JPanel();
		JPanel tButtonPanel2 = new JPanel();
		JPanel tButtonPanel3 = new JPanel();
		JPanel tButtonPanel4 = new JPanel();
		tButtonPanel1.add(löschenButton);
		tButtonPanel2.add(trackerErstellenButton);
		tButtonPanel3.add(trackerEintragenButton);
		tButtonPanel4.add(alleTrackerAnzeigen);
		trackerGridPanel.add(tButtonPanel1);
		trackerGridPanel.add(tButtonPanel2);
		trackerGridPanel.add(tButtonPanel3);
		trackerGridPanel.add(tButtonPanel4);

		trackerPanel.add(trackerID);
		trackerPanel.add(trackerZuverl);
		trackerPanel.add(trackerGridPanel);

		ändernButton
				.setToolTipText("Ändert die in der Tabelle gewählte Meldung entsprechend den oben eingetragenen Werten ab");
		inaktivButton
				.setToolTipText("Setzt die gewählte Meldung auf inaktiv, damit wird sie in für die App-Benutzer nicht mehr angezeigt");

		JPanel artPanel = new JPanel();
		artPanel.add(art);

		meldungsPanel.add(artPanel);
		meldungsPanel.add(ort);
		meldungsPanel.add(beschreibung);
		meldungsPanel.add(zeit);
		meldungsPanel.add(aktive);
		meldungsPanel.add(inaktive);
		meldungsPanel.add(zuverl);
		meldungsPanel.add(meldungGridPanel);

		GridBagConstraints c = new GridBagConstraints();

		c.gridx = 0;
		c.gridy = 0;
		c.weightx = 1.0;
		c.weighty = 0.8;
		c.fill = GridBagConstraints.BOTH;

		infoPanel.add(meldungsPanel, c);

		c.gridx = 0;
		c.gridy = 1;
		c.weightx = 1.0;
		c.weighty = 0.2;
		c.fill = GridBagConstraints.BOTH;
		infoPanel.add(trackerPanel, c);

		basisPanel.add(new JScrollPane(table));
		basisPanel.add(infoPanel);

		this.add(basisPanel, BorderLayout.CENTER);
		this.add(statusLeiste, BorderLayout.SOUTH);

		this.setVisible(true);

		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				running = false;
			}
		});

		// Bei Auswählen eines Tabelleneintrags
		table.getSelectionModel().addListSelectionListener(
				new ListSelectionListener() {

					@Override
					public void valueChanged(ListSelectionEvent e) {
						Meldung m = getSelectedMeldung();
						if (m != null) {
							// Tracker-Info herunterladen. Alten DownloadThread
							// stoppen, falls er noch läuft.
							if (trackerInfoDownload != null
									&& trackerInfoDownload.isAlive()) {
								try {
									trackerInfoDownload.join();
								} catch (InterruptedException e1) {
								}
							}
							tLadeBalken.setIndeterminate(true);
							trackerInfoDownload = new TrackerInfoDownload(m
									.getTracker_id(), tLadeBalken, trackerID,
									trackerZuverl);
							trackerInfoDownload.start();

							int i = 0;
							for (i = 0; i < meldungsTypen.length; i++)
								if (meldungsTypen[i].equals(m.getArt()))
									break;
							art.setSelectedIndex(i);
							ort.setTextFieldText(m.getOrt());
							beschreibung.setTextFieldText(m.getBeschreibung());
							zeit.setTextFieldText(m.getZeitDifferenzText());
							aktive.setTextFieldText(Integer.toString(m
									.getAnzAktiv()));
							inaktive.setTextFieldText(Integer.toString(m
									.getAnzInaktiv()));
							double z = 0;
							if (m.getAnzAktiv() + m.getAnzInaktiv() != 0)
								z = (double) m.getAnzAktiv()
										/ ((double) m.getAnzAktiv() + (double) m
												.getAnzInaktiv());
							zuverl.setTextFieldText(Double.toString(z));
						}

					}
				});

		table.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getButton() == MouseEvent.BUTTON1
						&& e.getClickCount() == 2) {
					// Doppelklick mit linker Maustaste
					try {
						Meldung m = getSelectedMeldung();
						String[] data = {
								Double.toString(m.getKoordinaten()
										.getLatitude()),
								Double.toString(m.getKoordinaten()
										.getLongitude()), m.getOrt(),
								m.getArt(), m.getBeschreibung() };
						BufferedWriter writer = new BufferedWriter(
								new FileWriter(new File("data.txt")));
						for (int i = 0; i < data.length; i++) {
							data[i] = StringEscapeUtils.escapeHtml4(data[i]);
							writer.write(data[i]);
							writer.newLine();
						}
						writer.close();

						File f = new File("maps.html");
						URIBuilder builder = new URIBuilder();
						builder.setPath(f.getAbsolutePath().replace((char) 92,
								(char) 47));
						builder.setScheme("file");
						String url = URLDecoder.decode(builder.build().toURL()
								.toString(), "UTF-8");

						BrowserLauncher launcher = new BrowserLauncher();
						launcher.openURLinBrowser(url);
						// openURL(url);
					} catch (MalformedURLException e1) {
						e1.printStackTrace();
					} catch (IOException e1) {
						e1.printStackTrace();
					} catch (URISyntaxException e1) {
						e1.printStackTrace();
					} catch (BrowserLaunchingInitializingException e1) {
						e1.printStackTrace();
					} catch (UnsupportedOperatingSystemException e1) {
						e1.printStackTrace();
					}
				}
			}
		});

		inaktivButton.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				// Meldung inaktiv schalten
				ladeBalken.setIndeterminate(true);
				GUI.this.setCursor(Cursor
						.getPredefinedCursor(Cursor.WAIT_CURSOR));
				String id = (String) table.getModel().getValueAt(
						table.getSelectedRow(), 0);
				MeldungVerwaltenThread thread = new MeldungVerwaltenThread(id,
						ladeBalken, GUI.this, false, table);
				thread.start();
			}
		});

		ändernButton.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				// Meldung ändern
				ladeBalken.setIndeterminate(true);
				GUI.this.setCursor(Cursor
						.getPredefinedCursor(Cursor.WAIT_CURSOR));
				String id = (String) table.getModel().getValueAt(
						table.getSelectedRow(), 0);
				int index = 0;
				if (art.getSelectedIndex() == 0)
					index = 1;
				else
					index = art.getSelectedIndex();
				MeldungVerwaltenThread thread = new MeldungVerwaltenThread(id,
						meldungsTypen[index], ort.getText(), beschreibung
								.getText(), ladeBalken, GUI.this, table);
				thread.start();
			}
		});

		löschenButton.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				Meldung m = getSelectedMeldung();
				int auswahl = JOptionPane.showConfirmDialog(
						GUI.this,
						"Trucker "
								+ m.getTracker_id()
								+ " und alle seine Meldungen werden damit endgültig gelöscht!",
						"Achtung", JOptionPane.WARNING_MESSAGE);
				if (auswahl == 0) {
					GUI.this.setCursor(Cursor
							.getPredefinedCursor(Cursor.WAIT_CURSOR));
					tLadeBalken.setIndeterminate(true);
					TrackerVerwaltenThread tvThread = new TrackerVerwaltenThread(
							TrackerVerwaltungAction.TRACKER_LÖSCHEN,
							tLadeBalken, m.getTracker_id(), GUI.this);
					tvThread.start();
				}
			}
		});

		meldungErstellenButton.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent arg0) {
				erstelleMeldungsErstellDialog();
			}
		});

		trackerErstellenButton.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				GUI.this.setCursor(Cursor
						.getPredefinedCursor(Cursor.WAIT_CURSOR));
				tLadeBalken.setIndeterminate(true);
				TrackerVerwaltenThread tvThread = new TrackerVerwaltenThread(
						TrackerVerwaltungAction.TRACKER_ERSTELLEN, tLadeBalken,
						null, GUI.this);
				tvThread.start();
			}
		});

		trackerEintragenButton.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				String eingabe = JOptionPane.showInputDialog(GUI.this,
						"Trucker-ID eintragen:");
				if (eingabe != null && !eingabe.equals("")) {
					// OK gedrückt und nicht "" eingegeben
					GUI.this.setCursor(Cursor
							.getPredefinedCursor(Cursor.WAIT_CURSOR));
					tLadeBalken.setIndeterminate(true);
					TrackerVerwaltenThread tv = new TrackerVerwaltenThread(
							TrackerVerwaltungAction.TRACKER_EINTRAGEN,
							tLadeBalken, eingabe, GUI.this);
					tv.start();
				}
			}
		});

		alleTrackerAnzeigen.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				GUI.this.setCursor(Cursor
						.getPredefinedCursor(Cursor.WAIT_CURSOR));
				tLadeBalken.setIndeterminate(true);
				TrackerDownloadThread tdt = new TrackerDownloadThread(GUI.this,
						tLadeBalken);
				tdt.start();
			}
		});

		meldungLöschenButton.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				ladeBalken.setIndeterminate(true);
				GUI.this.setCursor(Cursor
						.getPredefinedCursor(Cursor.WAIT_CURSOR));
				String id = (String) table.getModel().getValueAt(
						table.getSelectedRow(), 0);
				MeldungVerwaltenThread mvThread = new MeldungVerwaltenThread(
						id, ladeBalken, GUI.this, true, table);
				mvThread.start();
			}
		});

	}

	/**
	 * Liefert die gerade ausgewählte Meldung zurück.
	 * 
	 * @return die Meldung
	 */
	private Meldung getSelectedMeldung() {
		int index = table.getSelectedRow();
		if (index < 0)
			index = 0;
		String id = (String) table.getModel().getValueAt(index, 0);
		Meldung m = null;
		for (Meldung tmp : MeldungsDownload.meldungsListe)
			if (tmp.getMeldung_id().equals(id)) {
				m = tmp;
				break;
			}
		return m;
	}

	private void erstelleMeldungsErstellDialog() {
		final JDialog dialog = new JDialog();
		dialog.setBounds(this.getX() + 100, this.getY() + 50, 500, 400);
		dialog.setLayout(new GridLayout(6, 1));

		JButton erstellen = new JButton("Meldung erstellen");
		final JComboBox<String> art = new JComboBox<String>();
		for (int i = 0; i < meldungsTypen.length; i++)
			art.addItem(meldungsTypen[i]);
		final JTextField ort = new JTextField();
		final JTextField beschreibung = new JTextField();
		final JTextField lat = new JTextField();
		final JTextField lng = new JTextField();
		PromptSupport.setPrompt("Latitude", lat);
		PromptSupport.setPrompt("Longitude", lng);
		PromptSupport.setPrompt("Ort", ort);
		PromptSupport.setPrompt("Beschreibung...", beschreibung);

		dialog.add(art);
		dialog.add(lat);
		dialog.add(lng);
		dialog.add(ort);
		dialog.add(beschreibung);
		dialog.add(erstellen);

		erstellen.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (art.getSelectedIndex() != 0 && ort.getText().length() != 0
						&& beschreibung.getText().length() != 0
						&& lat.getText().length() != 0
						&& lng.getText().length() != 0) {
					Meldung m = new Meldung(art.getSelectedItem().toString(),
							ort.getText(), TRACKER_ID_RADIO2000, "0",
							beschreibung.getText(), new Timestamp(System
									.currentTimeMillis()), new GPSKoordinaten(
									Double.parseDouble(lat.getText()), Double
											.parseDouble(lng.getText())), 0, 0);
					MeldungErstellenThread met = new MeldungErstellenThread(m,
							ladeBalken, dialog);
					ladeBalken.setIndeterminate(true);
					dialog.setCursor(Cursor
							.getPredefinedCursor(Cursor.WAIT_CURSOR));
					met.start();
				} else
					JOptionPane.showConfirmDialog(GUI.this,
							"Alle Textfelder müssen gefüllt sein!", "Achtung!",
							JOptionPane.ERROR_MESSAGE);
			}
		});

		dialog.setVisible(true);
	}
}
